home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume14 / cdecl2 / part02 < prev    next >
Encoding:
Internet Message Format  |  1988-05-09  |  27.4 KB

  1. Subject:  v14i091:  New version of Cdecl, parse C declarations, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: cbosgd!pegasus!hansen (Tony Hansen)
  7. Posting-number: Volume 14, Issue 91
  8. Archive-name: cdecl2/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 2 (of 2)."
  17. # Contents:  cdecl.c
  18. # Wrapped by rsalz@fig.bbn.com on Mon May  9 20:40:48 1988
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'cdecl.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'cdecl.c'\"
  22. else
  23. echo shar: Extracting \"'cdecl.c'\" \(25555 characters\)
  24. sed "s/^X//" >'cdecl.c' <<'END_OF_FILE'
  25. X/*
  26. X * cdecl - ANSI C and C++ declaration composer & decoder
  27. X *
  28. X *    originally written
  29. X *        Graham Ross
  30. X *        once at tektronix!tekmdp!grahamr
  31. X *        now at Context, Inc.
  32. X *
  33. X *    modified to provide hints for unsupported types
  34. X *    added argument lists for functions
  35. X *    added 'explain cast' grammar
  36. X *    added #ifdef for 'create program' feature
  37. X *        ???? (sorry, I lost your name and login)
  38. X *
  39. X *    conversion to ANSI C
  40. X *        David Wolverton
  41. X *        ihnp4!houxs!daw
  42. X *
  43. X *    merged D. Wolverton's ANSI C version w/ ????'s version
  44. X *    added function prototypes
  45. X *    added C++ declarations
  46. X *    made type combination checking table driven
  47. X *    added checks for void variable combinations
  48. X *    made 'create program' feature a runtime option
  49. X *    added file parsing as well as just stdin
  50. X *    added help message at beginning
  51. X *    added prompts when on a TTY or in interactive mode
  52. X *    added getopt() usage
  53. X *    added -a, -r, -p, -c, -d, -D, -V, -i and -+ options
  54. X *    delinted
  55. X *    added #defines for those without getopt or void
  56. X *    added 'set options' command
  57. X *    added 'quit/exit' command
  58. X *    added synonyms
  59. X *        Tony Hansen
  60. X *        attmail!tony, ihnp4!pegasus!hansen
  61. X *
  62. X *    added extern, register, static
  63. X *    added links to explain, cast, declare
  64. X *    separately developed ANSI C support
  65. X *        Merlyn LeRoy
  66. X *        merlyn@rose3.rosemount.com
  67. X *
  68. X *    merged versions from LeRoy
  69. X *    added tmpfile() support
  70. X *    allow more parts to be missing during explanations
  71. X *        Tony Hansen
  72. X *        attmail!tony, ihnp4!pegasus!hansen
  73. X */
  74. X
  75. char cdeclsccsid[] = "@(#)cdecl.c    2.4 3/31/88";
  76. X
  77. X#include <stdio.h>
  78. X#include <ctype.h>
  79. X#if __STDC__ || defined(DOS)
  80. X# include <stdlib.h>
  81. X# include <stddef.h>
  82. X# include <string.h>
  83. X# include <stdarg.h>
  84. X#else
  85. X# ifndef NOVARARGS
  86. X#  include <varargs.h>
  87. X# endif /* ndef NOVARARGS */
  88. char *malloc();
  89. void free(), exit(), perror();
  90. X# ifdef BSD
  91. X#  include <strings.h>
  92. X   extern int errno;
  93. X#  define strrchr rindex
  94. X#  define NOTMPFILE
  95. X# else
  96. X#  include <string.h>
  97. X#  include <errno.h>
  98. X# endif /* BSD */
  99. X# ifdef NOVOID
  100. X#  define void int
  101. X# endif /* NOVOID */
  102. X#endif /* __STDC__ || DOS */
  103. X
  104. X#define    MB_SHORT    0001
  105. X#define    MB_LONG        0002
  106. X#define    MB_UNSIGNED    0004
  107. X#define MB_INT        0010
  108. X#define MB_CHAR        0020
  109. X#define MB_FLOAT    0040
  110. X#define MB_DOUBLE    0100
  111. X#define MB_VOID        0200
  112. X#define    MB_SIGNED    0400
  113. X
  114. X#define NullCP ((char*)NULL)
  115. X#ifdef dodebug
  116. X# define Debug(x) do { if (DebugFlag) (void) fprintf x; } while (0)
  117. X#else
  118. X# define Debug(x) /* nothing */
  119. X#endif
  120. X
  121. X#if __STDC__
  122. X  char *ds(char *), *cat(char *, ...), *visible(int);
  123. X  int getopt(int,char **,char *);
  124. X  int main(int, char **);
  125. X  int yywrap(void);
  126. X  int dostdin(void);
  127. X  void mbcheck(void), dohelp(void), usage(void);
  128. X  void prompt(void), doprompt(void), noprompt(void);
  129. X  void unsupp(char *, char *);
  130. X  void notsupported(char *, char *, char *);
  131. X  void yyerror(char *);
  132. X  void doset(char *);
  133. X  void dodeclare(char*, char*, char*, char*, char*);
  134. X  void docast(char*, char*, char*, char*);
  135. X  void dodexplain(char*, char*, char*, char*);
  136. X  void docexplain(char*, char*, char*, char*);
  137. X  void setprogname(char *);
  138. X  int dotmpfile(int, char**), dofileargs(int, char**);
  139. X#else
  140. X  char *ds(), *cat(), *visible();
  141. X  int getopt();
  142. X  void mbcheck(), dohelp(), usage();
  143. X  void prompt(), doprompt(), noprompt();
  144. X  void unsupp(), notsupported();
  145. X  void yyerror();
  146. X  void doset(), dodeclare(), docast(), dodexplain(), docexplain();
  147. X  void setprogname();
  148. X  int dotmpfile(), dofileargs();
  149. X#endif /* __STDC__ */
  150. X  FILE *tmpfile();
  151. X
  152. X/* variables used during parsing */
  153. unsigned modbits = 0;
  154. int arbdims = 1;
  155. char *savedname = 0;
  156. char unknown_name[] = "unknown_name";
  157. char prev = 0;        /* the current type of the variable being examined */
  158. X            /*    values    type                   */
  159. X            /*    p    pointer                   */
  160. X            /*    r    reference               */
  161. X            /*    f    function               */
  162. X            /*    a    array (of arbitrary dimensions)    */
  163. X            /*    A    array with dimensions           */
  164. X            /*    n    name                   */
  165. X            /*    v    void                   */
  166. X            /*    s    struct | class               */
  167. X            /*    t    simple type (int, long, etc.)       */
  168. X
  169. X/* options */
  170. int RitchieFlag = 0;        /* -r, assume Ritchie PDP C language */
  171. int MkProgramFlag = 0;        /* -c, output {} and ; after declarations */
  172. int PreANSIFlag = 0;        /* -p, assume pre-ANSI C language */
  173. int CplusplusFlag = 0;        /* -+, assume C++ language */
  174. int OnATty = 0;            /* stdin is coming from a terminal */
  175. int Interactive = 0;        /* -i, overrides OnATty */
  176. int KeywordName = 0;        /* $0 is a keyword (declare, explain, cast) */
  177. char *progname = "cdecl";    /* $0 */
  178. X
  179. X#if dodebug
  180. int DebugFlag = 0;        /* -d, output debugging trace info */
  181. X#endif
  182. X
  183. X#ifdef doyydebug        /* compile in yacc trace statements */
  184. X#define YYDEBUG 1
  185. X#endif /* doyydebug */
  186. X
  187. X#include "cdgram.c"
  188. X#include "cdlex.c"
  189. X
  190. X/* definitions (and abbreviations) for type combinations cross check table */
  191. X#define ALWAYS    0    /* combo always okay */
  192. X#define _    ALWAYS
  193. X#define NEVER    1    /* combo never allowed */
  194. X#define X    NEVER
  195. X#define RITCHIE    2    /* combo not allowed in Ritchie compiler */
  196. X#define R    RITCHIE
  197. X#define PREANSI    3    /* combo not allowed in Pre-ANSI compiler */
  198. X#define P    PREANSI
  199. X#define ANSI    4    /* combo not allowed anymore in ANSI compiler */
  200. X#define A    ANSI
  201. X
  202. X/* This is an lower left triangular array. If we needed */
  203. X/* to save 9 bytes, the "long" row can be removed. */
  204. char crosscheck[9][9] = {
  205. X    /*            L, I, S, C, V, U, S, F, D, */
  206. X    /* long */        _, _, _, _, _, _, _, _, _,
  207. X    /* int */        _, _, _, _, _, _, _, _, _,
  208. X    /* short */        X, _, _, _, _, _, _, _, _,
  209. X    /* char */        X, X, X, _, _, _, _, _, _,
  210. X    /* void */        X, X, X, X, _, _, _, _, _,
  211. X    /* unsigned */    R, _, R, R, X, _, _, _, _,
  212. X    /* signed */    P, P, P, P, X, X, _, _, _,
  213. X    /* float */        A, X, X, X, X, X, X, _, _,
  214. X    /* double */    P, X, X, X, X, X, X, X, _
  215. X};
  216. X
  217. X/* the names and bits checked for each row in the above array */
  218. struct
  219. X    {
  220. X    char *name;
  221. X    int bit;
  222. X    } crosstypes[9] =
  223. X    {
  224. X        { "long",        MB_LONG        },
  225. X        { "int",        MB_INT        },
  226. X        { "short",        MB_SHORT    },
  227. X        { "char",        MB_CHAR        },
  228. X        { "void",        MB_VOID        },
  229. X        { "unsigned",    MB_UNSIGNED    },
  230. X        { "signed",        MB_SIGNED    },
  231. X        { "float",        MB_FLOAT    },
  232. X        { "double",        MB_DOUBLE    }
  233. X    };
  234. X
  235. X/* Run through the crosscheck array looking */
  236. X/* for unsupported combinations of types. */
  237. void mbcheck()
  238. X{
  239. X    register int i, j, restrict;
  240. X    char *t1, *t2;
  241. X
  242. X    /* Loop through the types */
  243. X    /* (skip the "long" row) */
  244. X    for (i = 1; i < 9; i++)
  245. X    {
  246. X    /* if this type is in use */
  247. X    if ((modbits & crosstypes[i].bit) != 0)
  248. X        {
  249. X        /* check for other types also in use */
  250. X        for (j = 0; j < i; j++)
  251. X        {
  252. X        /* this type is not in use */
  253. X        if (!(modbits & crosstypes[j].bit))
  254. X            continue;
  255. X        /* check the type of restriction */
  256. X        restrict = crosscheck[i][j];
  257. X        if (restrict == ALWAYS)
  258. X            continue;
  259. X        t1 = crosstypes[i].name;
  260. X        t2 = crosstypes[j].name;
  261. X        if (restrict == NEVER)
  262. X            {
  263. X            notsupported("", t1, t2);
  264. X            }
  265. X        else if (restrict == RITCHIE)
  266. X            {
  267. X            if (RitchieFlag)
  268. X            notsupported(" (Ritchie Compiler)", t1, t2);
  269. X            }
  270. X        else if (restrict == PREANSI)
  271. X            {
  272. X            if (PreANSIFlag || RitchieFlag)
  273. X            notsupported(" (Pre-ANSI Compiler)", t1, t2);
  274. X            }
  275. X        else if (restrict == ANSI)
  276. X            {
  277. X            if (!RitchieFlag && !PreANSIFlag)
  278. X            notsupported(" (ANSI Compiler)", t1, t2);
  279. X            }
  280. X        else
  281. X            {
  282. X            (void) fprintf (stderr,
  283. X            "%s: Internal error in crosscheck[%d,%d]=%d!\n",
  284. X            progname, i, j, restrict);
  285. X            exit(1); /* NOTREACHED */
  286. X            }
  287. X        }
  288. X        }
  289. X    }
  290. X}
  291. X
  292. X/* undefine these as they are no longer needed */
  293. X#undef _
  294. X#undef ALWAYS
  295. X#undef X
  296. X#undef NEVER
  297. X#undef R
  298. X#undef RITCHIE
  299. X#undef P
  300. X#undef PREANSI
  301. X#undef A
  302. X#undef ANSI
  303. X
  304. X/* Write out a message about something */
  305. X/* being unsupported, possibly with a hint. */
  306. void unsupp(s,hint)
  307. char *s,*hint;
  308. X{
  309. X    notsupported("", s, NullCP);
  310. X    if (hint)
  311. X    (void) fprintf(stderr, "\t(maybe you mean \"%s\")\n", hint);
  312. X}
  313. X
  314. X/* Write out a message about something */
  315. X/* being unsupported on a particular compiler. */
  316. void notsupported(compiler, type1, type2)
  317. char *compiler, *type1, *type2;
  318. X{
  319. X    if (type2)
  320. X    (void) fprintf(stderr,
  321. X        "Warning: Unsupported in%s C%s -- '%s' with '%s'\n",
  322. X        compiler, CplusplusFlag ? "++" : "", type1, type2);
  323. X    else
  324. X    (void) fprintf(stderr,
  325. X        "Warning: Unsupported in%s C%s -- '%s'\n",
  326. X        compiler, CplusplusFlag ? "++" : "", type1);
  327. X}
  328. X
  329. X/* Called by the yacc grammar */
  330. void yyerror(s)
  331. char *s;
  332. X{
  333. X    (void) printf("%s\n",s);
  334. X    Debug((stdout, "yychar=%d\n", yychar));
  335. X}
  336. X
  337. X/* Called by the yacc grammar */
  338. int yywrap()
  339. X{
  340. X    return 1;
  341. X}
  342. X
  343. X/*
  344. X * Support for dynamic strings:
  345. X * cat() creates a string from the concatenation
  346. X * of a null terminated list of input strings.
  347. X * The input strings are free()'d by cat()
  348. X * (so they better have been malloc()'d).
  349. X *
  350. X * the different methods of <stdarg.h> and
  351. X * <vararg.h> are handled within these macros
  352. X */
  353. X#if __STDC__
  354. X#  define VA_DCL(type,var)        (type var,...)
  355. X#  define VA_START(list,var,type)    ((va_start(list,var)) , (var))
  356. X#else
  357. X#if defined(DOS)
  358. X#  define VA_DCL(type,var)        (var,...) type var;
  359. X#  define VA_START(list,var,type)    ((va_start(list,var)) , (var))
  360. X#else
  361. X#ifndef NOVARARGS
  362. X# define VA_DCL(type,var)        (va_alist) va_dcl
  363. X# define VA_START(list,var,type)    ((va_start(list)) , va_arg(list,type))
  364. X#else
  365. X   /*
  366. X    *    it is assumed here that machines which don't have either
  367. X    *    <varargs.h> or <stdarg.h> will put its arguments on
  368. X    *    the stack in the "usual" way and consequently can grab
  369. X    *    the arguments using the "take the address of the first
  370. X    *    parameter and increment by sizeof" trick.
  371. X    */
  372. X# define VA_DCL(type,var)        (var) type var;
  373. X# define VA_START(list,var,type)    (list = (va_list)&(var) , (var))
  374. X# define va_arg(list,type)        ((type *)(list += sizeof(type)))[-1]
  375. X# define va_end(p)            /* nothing */
  376. typedef char *va_list;
  377. X#endif /* NOVARARGS */
  378. X#endif /* DOS */
  379. X#endif /* __STDC__ */
  380. X
  381. X/* VARARGS */
  382. char *cat
  383. VA_DCL(char*, s1)
  384. X{
  385. X    register char *newstr;
  386. X    register unsigned len = 1;
  387. X    char *str;
  388. X    va_list args;
  389. X
  390. X    /* find the length which needs to be allocated */
  391. X    str = VA_START(args, s1, char*);
  392. X    for ( ; str; str = va_arg(args, char*))
  393. X    len += strlen(str);
  394. X    va_end(args);
  395. X
  396. X    /* allocate it */
  397. X    newstr = malloc(len);
  398. X    if (newstr == 0)
  399. X    {
  400. X    (void) fprintf (stderr, "%s: out of malloc space within cat()!\n",
  401. X        progname);
  402. X    exit(1);
  403. X    }
  404. X    newstr[0] = '\0';
  405. X
  406. X    /* copy in the strings */
  407. X    str = VA_START(args, s1, char*);
  408. X    for ( ; str; str = va_arg(args, char*))
  409. X    {
  410. X    (void) strcat(newstr,str);
  411. X    free(str);
  412. X    }
  413. X    va_end(args);
  414. X
  415. X    Debug((stderr, "\tcat created '%s'\n", newstr));
  416. X    return newstr;
  417. X}
  418. X
  419. X/*
  420. X * ds() makes a malloc()'d string from one that's not.
  421. X */
  422. char *ds(s)
  423. char *s;
  424. X{
  425. X    register char *p = malloc((unsigned)(strlen(s)+1));
  426. X
  427. X    if (p)
  428. X    (void) strcpy(p,s);
  429. X    else
  430. X    {
  431. X    (void) fprintf (stderr, "%s: malloc() failed!\n", progname);
  432. X    exit(1);
  433. X    }
  434. X    return p;
  435. X}
  436. X
  437. X/* return a visible representation of a character */
  438. char *visible(c)
  439. int c;
  440. X{
  441. X    static char buf[5];
  442. X
  443. X    c &= 0377;
  444. X    if (isprint(c))
  445. X    {
  446. X    buf[0] = c;
  447. X    buf[1] = '\0';
  448. X    }
  449. X    else
  450. X    (void) sprintf(buf,"\\%03o",c);
  451. X    return buf;
  452. X}
  453. X
  454. X#ifdef NOTMPFILE
  455. X/* provide a conservative version of tmpfile() */
  456. X/* for those systems without it. */
  457. X/* tmpfile() returns a FILE* of a file opened */
  458. X/* for read&write. It is supposed to be */
  459. X/* automatically removed when it gets closed, */
  460. X/* but here we provide a separate rmtmpfile() */
  461. X/* function to perform that function. */
  462. X/* Also provide several possible file names to */
  463. X/* try for opening. */
  464. static char *file4tmpfile = 0;
  465. X
  466. XFILE *tmpfile()
  467. X{
  468. X    static char *listtmpfiles[] =
  469. X    {
  470. X    "/usr/tmp/cdeclXXXXXX",
  471. X    "/tmp/cdeclXXXXXX",
  472. X    "/cdeclXXXXXX",
  473. X    "cdeclXXXXXX",
  474. X    0
  475. X    };
  476. X
  477. X    char **listp = listtmpfiles;
  478. X    for ( ; *listp; listp++)
  479. X    {
  480. X    FILE *retfp;
  481. X    (void) mktemp(*listp);
  482. X    retfp = fopen(*listp, "w+");
  483. X    if (!retfp)
  484. X        continue;
  485. X    file4tmpfile = *listp;
  486. X    return retfp;
  487. X    }
  488. X
  489. X    return 0;
  490. X}
  491. X
  492. void rmtmpfile()
  493. X{
  494. X    if (file4tmpfile)
  495. X    (void) unlink(file4tmpfile);
  496. X}
  497. X#else
  498. X/* provide a mock rmtmpfile() for normal systems */
  499. X# define rmtmpfile()    /* nothing */
  500. X#endif /* NOTMPFILE */
  501. X
  502. X#ifndef NOGETOPT
  503. extern int optind;
  504. X#else
  505. X/* This is a miniature version of getopt() which will */
  506. X/* do just barely enough for us to get by below. */
  507. X/* Options are not allowed to be bunched up together. */
  508. X/* Option arguments are not supported. */
  509. int optind = 1;
  510. X
  511. int getopt(argc,argv,optstring)
  512. char **argv;
  513. char *optstring;
  514. X{
  515. X    int ret;
  516. X    char *p;
  517. X
  518. X    if ((argv[optind][0] != '-')
  519. X#ifdef DOS
  520. X    && (argv[optind][0] != '/')
  521. X#endif /* DOS */
  522. X    )
  523. X    return EOF;
  524. X
  525. X    ret = argv[optind][1];
  526. X    optind++;
  527. X
  528. X    for (p = optstring; *p; p++)
  529. X    if (*p == ret)
  530. X        return ret;
  531. X
  532. X    (void) fprintf (stderr, "%s: illegal option -- %s\n",
  533. X    progname, visible(ret));
  534. X
  535. X    return '?';
  536. X}
  537. X#endif
  538. X
  539. X/* the help messages */
  540. struct helpstruct
  541. X    {
  542. X    char *text;    /* generic text */
  543. X    char *cpptext;    /* C++ specific text */
  544. X    } helptext[] =
  545. X    {    /* up-to 23 lines of help text so it fits on (24x80) screens */
  546. X/*  1 */{ "[] means optional; {} means 1 or more; <> means defined elsewhere", 0 },
  547. X/*  2 */{ "  commands are separated by ';' and newlines", 0 },
  548. X/*  3 */{ "command:", 0 },
  549. X/*  4 */{ "  declare <name> as <english>", 0 },
  550. X/*  5 */{ "  cast <name> into <english>", 0 },
  551. X/*  6 */{ "  explain <gibberish>", 0 },
  552. X/*  7 */{ "  set or set options", 0 },
  553. X/*  8 */{ "  help, ?", 0 },
  554. X/*  9 */{ "  quit or exit", 0 },
  555. X/* 10 */{ "english:", 0 },
  556. X/* 11 */{ "  function [( <decl-list> )] returning <english>", 0 },
  557. X/* 12 */{ "  array [<number>] of <english>", 0 },
  558. X/* 13 */{ "  [{ const | volatile | noalias }] pointer to <english>",
  559. X      "  [{const|volatile}] {pointer|reference} to [member of class <name>] <english>" },
  560. X/* 14 */{ "  <type>", 0 },
  561. X/* 15 */{ "type:", 0 },
  562. X/* 16 */{ "  {[<storage-class>] [{<modifier>}] [<C-type>]}", 0 },
  563. X/* 17 */{ "  { struct | union | enum } <name>",
  564. X      "  {struct|class|union|enum} <name>" },
  565. X/* 18 */{ "decllist: a comma separated list of <name>, <english> or <name> as <english>", 0 },
  566. X/* 19 */{ "name: a C identifier", 0 },
  567. X/* 20 */{ "gibberish: a C declaration, like 'int *x', or cast, like '(int *)x'", 0 },
  568. X/* 21 */{ "storage-class: extern, static, auto, register", 0 },
  569. X/* 22 */{ "C-type: int, char, float, double, or void", 0 },
  570. X/* 23 */{ "modifier: short, long, signed, unsigned, const, volatile, or noalias",
  571. X      "modifier: short, long, signed, unsigned, const, or volatile" },
  572. X    { 0, 0 }
  573. X    };
  574. X
  575. X/* Print out the help text */
  576. void dohelp()
  577. X{
  578. X    register struct helpstruct *p;
  579. X    register char *fmt = CplusplusFlag ? " %s\n" : "\t%s\n";
  580. X
  581. X    for (p = helptext; p->text; p++)
  582. X    if (CplusplusFlag && p->cpptext)
  583. X        (void) printf(fmt, p->cpptext);
  584. X    else
  585. X        (void) printf(fmt, p->text);
  586. X}
  587. X
  588. X/* Tell how to invoke cdecl. */
  589. void usage()
  590. X{
  591. X    (void) fprintf (stderr, "Usage: %s [-r|-p|-a|-+] [-ci%s%s] [files...]\n",
  592. X    progname,
  593. X#ifdef dodebug
  594. X    "d",
  595. X#else
  596. X    "",
  597. X#endif /* dodebug */
  598. X#ifdef doyydebug
  599. X    "D"
  600. X#else
  601. X    ""
  602. X#endif /* doyydebug */
  603. X    );
  604. X    (void) fprintf (stderr, "\t-r Check against Ritchie PDP C Compiler\n");
  605. X    (void) fprintf (stderr, "\t-p Check against Pre-ANSI C Compiler\n");
  606. X    (void) fprintf (stderr, "\t-a Check against ANSI C Compiler%s\n",
  607. X    CplusplusFlag ? "" : " (the default)");
  608. X    (void) fprintf (stderr, "\t-+ Check against C++ Compiler%s\n",
  609. X    CplusplusFlag ? " (the default)" : "");
  610. X    (void) fprintf (stderr, "\t-c Create compilable output (include ; and {})\n");
  611. X    (void) fprintf (stderr, "\t-i Force interactive mode\n");
  612. X#ifdef dodebug
  613. X    (void) fprintf (stderr, "\t-d Turn on debugging mode\n");
  614. X#endif /* dodebug */
  615. X#ifdef doyydebug
  616. X    (void) fprintf (stderr, "\t-D Turn on YACC debugging mode\n");
  617. X#endif /* doyydebug */
  618. X    exit(1);
  619. X    /* NOTREACHED */
  620. X}
  621. X
  622. X/* Manage the prompts. */
  623. static int prompting = 1;
  624. X
  625. void doprompt() { prompting = 1; }
  626. void noprompt() { prompting = 0; }
  627. X
  628. void prompt()
  629. X{
  630. X    if ((OnATty || Interactive) && prompting) {
  631. X    (void) printf("%s> ", progname);
  632. X    (void) fflush(stdout);
  633. X    }
  634. X}
  635. X
  636. X/* Save away the name of the program from argv[0] */
  637. void setprogname(argv0)
  638. char *argv0;
  639. X{
  640. X#ifdef DOS
  641. X    char *dot;
  642. X#endif /* DOS */
  643. X
  644. X    progname = strrchr(argv0, '/');
  645. X
  646. X#ifdef DOS
  647. X    if (!progname)
  648. X    progname = strrchr(argv0, '\\');
  649. X#endif /* DOS */
  650. X
  651. X    if (progname)
  652. X    progname++;
  653. X    else
  654. X    progname = argv0;
  655. X
  656. X#ifdef DOS
  657. X    dot = strchr(progname, '.');
  658. X    if (dot)
  659. X    *dot = '\0';
  660. X    for (dot = progname; *dot; dot++)
  661. X    *dot = tolower(*dot);
  662. X#endif /* DOS */
  663. X}
  664. X
  665. X/* Run down the list of keywords to see if the */
  666. X/* program is being called named as one of them */
  667. X/* or the first argument is one of them. */
  668. int namedkeyword(argn)
  669. char *argn;
  670. X{
  671. X    static char *cmdlist[] =
  672. X    {
  673. X    "explain", "declare", "cast", "help", "?", "set", 0
  674. X    };
  675. X
  676. X    /* first check the program name */
  677. X    char **cmdptr = cmdlist;
  678. X    for ( ; *cmdptr; cmdptr++)
  679. X    if (strcmp(*cmdptr, progname) == 0)
  680. X        {
  681. X        KeywordName = 1;
  682. X        return 1;
  683. X        }
  684. X
  685. X    /* now check $1 */
  686. X    for (cmdptr = cmdlist; *cmdptr; cmdptr++)
  687. X    if (strcmp(*cmdptr, argn) == 0)
  688. X        return 1;
  689. X
  690. X    /* nope, must be file name arguments */
  691. X    return 0;
  692. X}
  693. X
  694. X/* Read from standard input, turning */
  695. X/* on prompting if necessary. */
  696. int dostdin()
  697. X{
  698. X    int ret;
  699. X    OnATty = isatty(0);
  700. X    if (OnATty || Interactive)
  701. X    {
  702. X    (void) printf("Type `help' or `?' for help\n");
  703. X    prompt();
  704. X    }
  705. X
  706. X    yyin = stdin;
  707. X    ret = yyparse();
  708. X    OnATty = 0;
  709. X    return ret;
  710. X}
  711. X
  712. X/* Write the arguments into a file */
  713. X/* and treat that file as the input. */
  714. int dotmpfile(argc, argv)
  715. int argc;
  716. char **argv;
  717. X{
  718. X    int ret = 0;
  719. X    FILE *tmpfp = tmpfile();
  720. X    if (!tmpfp)
  721. X    {
  722. X    int sverrno = errno;
  723. X    (void) fprintf (stderr, "%s: cannot open temp file\n",
  724. X        progname);
  725. X    errno = sverrno;
  726. X    perror(progname);
  727. X    return 1;
  728. X    }
  729. X
  730. X    if (KeywordName)
  731. X    if (fputs(progname, tmpfp) == EOF)
  732. X        {
  733. X        int sverrno;
  734. X    errwrite:
  735. X        sverrno = errno;
  736. X        (void) fprintf (stderr, "%s: error writing to temp file\n",
  737. X        progname);
  738. X        errno = sverrno;
  739. X        perror(progname);
  740. X        (void) fclose(tmpfp);
  741. X        rmtmpfile();
  742. X        return 1;
  743. X        }
  744. X
  745. X    for ( ; optind < argc; optind++)
  746. X    if (fprintf(tmpfp, " %s", argv[optind]) == EOF)
  747. X        goto errwrite;
  748. X
  749. X    if (putc('\n', tmpfp) == EOF)
  750. X    goto errwrite;
  751. X
  752. X    rewind(tmpfp);
  753. X    yyin = tmpfp;
  754. X    ret += yyparse();
  755. X    (void) fclose(tmpfp);
  756. X    rmtmpfile();
  757. X
  758. X    return ret;
  759. X}
  760. X
  761. X/* Read each of the named files for input. */
  762. int dofileargs(argc, argv)
  763. int argc;
  764. char **argv;
  765. X{
  766. X    FILE *ifp;
  767. X    int ret = 0;
  768. X
  769. X    for ( ; optind < argc; optind++)
  770. X    if (strcmp(argv[optind], "-") == 0)
  771. X        ret += dostdin();
  772. X
  773. X    else if ((ifp = fopen(argv[optind], "r")) == NULL)
  774. X        {
  775. X        int sverrno = errno;
  776. X        (void) fprintf (stderr, "%s: cannot open %s\n",
  777. X        progname, argv[optind]);
  778. X        errno = sverrno;
  779. X        perror(argv[optind]);
  780. X        ret++;
  781. X        }
  782. X
  783. X    else
  784. X        {
  785. X        yyin = ifp;
  786. X        ret += yyparse();
  787. X        }
  788. X
  789. X    return ret;
  790. X}
  791. X
  792. X/* print out a cast */
  793. void docast(name, left, right, type)
  794. char *name, *left, *right, *type;
  795. X{
  796. X    int lenl = strlen(left), lenr = strlen(right);
  797. X
  798. X    if (prev == 'f')
  799. X        unsupp("Cast into function",
  800. X            "cast into pointer to function");
  801. X    else if (prev=='A' || prev=='a')
  802. X        unsupp("Cast into array","cast into pointer");
  803. X    (void) printf("(%s%*s%s)%s\n",
  804. X        type, lenl+lenr?lenl+1:0,
  805. X        left, right, name ? name : "expression");
  806. X    free(left);
  807. X    free(right);
  808. X    free(type);
  809. X    if (name)
  810. X        free(name);
  811. X}
  812. X
  813. X/* print out a declaration */
  814. void dodeclare(name, storage, left, right, type)
  815. char *name, *storage, *left, *right, *type;
  816. X{
  817. X    if (prev == 'v')
  818. X        unsupp("Variable of type void",
  819. X            "variable of type pointer to void");
  820. X
  821. X    if (*storage == 'r')
  822. X    switch (prev)
  823. X        {
  824. X        case 'f': unsupp("Register function", NullCP); break;
  825. X        case 'A':
  826. X        case 'a': unsupp("Register array", NullCP); break;
  827. X        case 's': unsupp("Register struct/class", NullCP); break;
  828. X        }
  829. X
  830. X    if (*storage)
  831. X        (void) printf("%s ", storage);
  832. X    (void) printf("%s %s%s%s",
  833. X        type, left,
  834. X    name ? name : (prev == 'f') ? "f" : "var", right);
  835. X    if (MkProgramFlag) {
  836. X        if ((prev == 'f') && (*storage != 'e'))
  837. X            (void) printf(" { }\n");
  838. X        else
  839. X            (void) printf(";\n");
  840. X    } else {
  841. X        (void) printf("\n");
  842. X    }
  843. X    free(storage);
  844. X    free(left);
  845. X    free(right);
  846. X    free(type);
  847. X    if (name)
  848. X        free(name);
  849. X}
  850. X
  851. void dodexplain(storage, constvol, type, decl)
  852. char *storage, *constvol, *type, *decl;
  853. X{
  854. X    if (type && (strcmp(type, "void") == 0))
  855. X    if (prev == 'n')
  856. X        unsupp("Variable of type void",
  857. X           "variable of type pointer to void");
  858. X    else if (prev == 'a')
  859. X        unsupp("array of type void",
  860. X           "array of type pointer to void");
  861. X    else if (prev == 'r')
  862. X        unsupp("reference to type void",
  863. X           "pointer to void");
  864. X
  865. X    if (*storage == 'r')
  866. X    switch (prev)
  867. X        {
  868. X        case 'f': unsupp("Register function", NullCP); break;
  869. X        case 'A':
  870. X        case 'a': unsupp("Register array", NullCP); break;
  871. X        case 's': unsupp("Register struct/union/enum/class", NullCP); break;
  872. X        }
  873. X
  874. X    (void) printf("declare %s as ", savedname);
  875. X    if (*storage)
  876. X        (void) printf("%s ", storage);
  877. X    (void) printf("%s", decl);
  878. X    if (*constvol)
  879. X        (void) printf("%s ", constvol);
  880. X    (void) printf("%s\n", type ? type : "int");
  881. X}
  882. X
  883. void docexplain(constvol, type, cast, name)
  884. char *constvol, *type, *cast, *name;
  885. X{
  886. X    if (strcmp(type, "void") == 0)
  887. X    if (prev == 'a')
  888. X        unsupp("array of type void",
  889. X           "array of type pointer to void");
  890. X    else if (prev == 'r')
  891. X        unsupp("reference to type void",
  892. X           "pointer to void");
  893. X    (void) printf("cast %s into %s", name, cast);
  894. X    if (strlen(constvol) > 0)
  895. X        (void) printf("%s ", constvol);
  896. X    (void) printf("%s\n",type);
  897. X}
  898. X
  899. X/* Do the appropriate things for the "set" command. */
  900. void doset(opt)
  901. char *opt;
  902. X{
  903. X    if (strcmp(opt, "create") == 0)
  904. X    { MkProgramFlag = 1; }
  905. X    else if (strcmp(opt, "nocreate") == 0)
  906. X    { MkProgramFlag = 0; }
  907. X    else if (strcmp(opt, "interactive") == 0)
  908. X    { Interactive = 1; }
  909. X    else if (strcmp(opt, "nointeractive") == 0)
  910. X    { Interactive = 0; OnATty = 0; }
  911. X    else if (strcmp(opt, "ritchie") == 0)
  912. X    { CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; }
  913. X    else if (strcmp(opt, "preansi") == 0)
  914. X    { CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; }
  915. X    else if (strcmp(opt, "ansi") == 0)
  916. X    { CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; }
  917. X    else if (strcmp(opt, "cplusplus") == 0)
  918. X    { CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; }
  919. X#ifdef dodebug
  920. X    else if (strcmp(opt, "debug") == 0)
  921. X    { DebugFlag = 1; }
  922. X    else if (strcmp(opt, "nodebug") == 0)
  923. X    { DebugFlag = 0; }
  924. X#endif /* dodebug */
  925. X#ifdef doyydebug
  926. X    else if (strcmp(opt, "yydebug") == 0)
  927. X    { yydebug = 1; }
  928. X    else if (strcmp(opt, "noyydebug") == 0)
  929. X    { yydebug = 0; }
  930. X#endif /* doyydebug */
  931. X    else
  932. X    {
  933. X    if ((strcmp(opt, unknown_name) != 0) &&
  934. X        (strcmp(opt, "options") != 0))
  935. X        (void) printf("Unknown set option: '%s'\n", opt);
  936. X
  937. X    (void) printf("Valid set options (and command line equivalents) are:\n");
  938. X    (void) printf("\toptions\n");
  939. X    (void) printf("\tcreate (-c), nocreate\n");
  940. X    (void) printf("\tinteractive (-i), nointeractive\n");
  941. X    (void) printf("\tritchie (-r), preansi (-p), ansi (-a) or cplusplus (-+)\n");
  942. X#ifdef dodebug
  943. X    (void) printf("\tdebug (-d), nodebug\n");
  944. X#endif /* dodebug */
  945. X#ifdef doyydebug
  946. X    (void) printf("\tyydebug (-D), noyydebug\n");
  947. X#endif /* doyydebug */
  948. X
  949. X    (void) printf("\nCurrent set values are:\n");
  950. X    (void) printf("\t%screate\n", MkProgramFlag ? "   " : " no");
  951. X    (void) printf("\t%sinteractive\n",
  952. X        (OnATty || Interactive) ? "   " : " no");
  953. X    if (RitchieFlag)
  954. X        (void) printf("\t   ritchie\n");
  955. X    else
  956. X        (void) printf("\t(noritchie)\n");
  957. X    if (PreANSIFlag)
  958. X        (void) printf("\t   preansi\n");
  959. X    else
  960. X        (void) printf("\t(nopreansi)\n");
  961. X    if (!RitchieFlag && !PreANSIFlag && !CplusplusFlag)
  962. X        (void) printf("\t   ansi\n");
  963. X    else
  964. X        (void) printf("\t(noansi)\n");
  965. X    if (CplusplusFlag)
  966. X        (void) printf("\t   cplusplus\n");
  967. X    else
  968. X        (void) printf("\t(nocplusplus)\n");
  969. X#ifdef dodebug
  970. X    (void) printf("\t%sdebug\n", DebugFlag ? "   " : " no");
  971. X#endif /* dodebug */
  972. X#ifdef doyydebug
  973. X    (void) printf("\t%syydebug\n", yydebug ? "   " : " no");
  974. X#endif /* doyydebug */
  975. X    }
  976. X}
  977. X
  978. void versions()
  979. X{
  980. X    (void) printf("Version:\n\t%s\n\t%s\n\t%s\n",
  981. X    cdeclsccsid, cdgramsccsid, cdlexsccsid);
  982. X    exit(0);
  983. X}
  984. X
  985. int main(argc, argv)
  986. char **argv;
  987. X{
  988. X    int c, ret = 0;
  989. X
  990. X    setprogname(argv[0]);
  991. X#ifdef DOS
  992. X    if (strcmp(progname, "cppdecl") == 0)
  993. X#else
  994. X    if (strcmp(progname, "c++decl") == 0)
  995. X#endif /* DOS */
  996. X    CplusplusFlag = 1;
  997. X
  998. X    while ((c = getopt(argc, argv, "cirpa+dDV")) != EOF)
  999. X    switch (c)
  1000. X        {
  1001. X        case 'c': MkProgramFlag=1; break;
  1002. X        case 'i': Interactive=1; break;
  1003. X
  1004. X        /* The following are mutually exclusive. */
  1005. X        /* Only the last one set prevails. */
  1006. X        case 'r': CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; break;
  1007. X        case 'p': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; break;
  1008. X        case 'a': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; break;
  1009. X        case '+': CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; break;
  1010. X
  1011. X#ifdef dodebug
  1012. X        case 'd': DebugFlag=1; break;
  1013. X#endif /* dodebug */
  1014. X#ifdef doyydebug
  1015. X        case 'D': yydebug=1; break;
  1016. X#endif /* doyydebug */
  1017. X        case 'V': versions(); break;
  1018. X        case '?': usage(); break;
  1019. X        }
  1020. X
  1021. X    /* Run down the list of arguments, parsing each one. */
  1022. X
  1023. X    /* Use standard input if no file names or "-" is found. */
  1024. X    if (optind == argc)
  1025. X    ret += dostdin();
  1026. X
  1027. X    /* If called as explain, declare or cast, or first */
  1028. X    /* argument is one of those, use the command line */
  1029. X    /* as the input. */
  1030. X    else if (namedkeyword(argv[optind]))
  1031. X    ret += dotmpfile(argc, argv);
  1032. X
  1033. X    else
  1034. X    ret += dofileargs(argc, argv);
  1035. X
  1036. X    exit(ret);
  1037. X    /* NOTREACHED */
  1038. X}
  1039. END_OF_FILE
  1040. if test 25555 -ne `wc -c <'cdecl.c'`; then
  1041.     echo shar: \"'cdecl.c'\" unpacked with wrong size!
  1042. fi
  1043. # end of 'cdecl.c'
  1044. fi
  1045. echo shar: End of archive 2 \(of 2\).
  1046. cp /dev/null ark2isdone
  1047. MISSING=""
  1048. for I in 1 2 ; do
  1049.     if test ! -f ark${I}isdone ; then
  1050.     MISSING="${MISSING} ${I}"
  1051.     fi
  1052. done
  1053. if test "${MISSING}" = "" ; then
  1054.     echo You have unpacked both archives.
  1055.     rm -f ark[1-9]isdone
  1056. else
  1057.     echo You still need to unpack the following archives:
  1058.     echo "        " ${MISSING}
  1059. fi
  1060. ##  End of shell archive.
  1061. exit 0
  1062.